"""
Invokes atlas commands based on the configuration module

>>> from mod454 import testconf
>>> execute( testconf )

"""
import atlas
from atlas import util
from functools import partial

def execute( conf ):
    """
    Executes a configuration file
    """

    attrs = [ "LOADER", "FITTER", "PREDICTOR", "EXPORTER" ]
    
    enabled = [ word + "_ENABLED" for word in attrs ]

    for funcattr, flagattr in zip( attrs, enabled ):
        # check the enabled flag
        if getattr(conf, flagattr):
            atlas.info("*** %s ***" % funcattr )
            tick = util.Tick()
            func = getattr( conf, funcattr )
            func( conf )
            atlas.info( "%s finished in %s" % (funcattr, tick.tock()))
        else:
            atlas.info("%s not enabled" % funcattr ) 

def producer( conf, formatter, strands ):
    """
    Produces data based on a configuration file and a formatter
    """
    from atlas import sql
    atlas.debug( "sql_uri='%s'" % conf.SQL_URI )
    atlas.info( "data dir='%s'" % conf.EXPORT_DIR )
    atlas.isdir( conf.EXPORT_DIR )

    # mixing the two SQLAlchemy approaches as
    # it seems the SA ORM wants to load everything into memory
    session = sql.get_session( conf.SQL_URI )
    engine  = sql.get_engine( conf.SQL_URI )
    
    for label_name in conf.EXPORT_LABELS:
        
        labels = list( session.query(sql.Label).filter(sql.Label.name==label_name) )
        if not labels:
            atlas.error( 'invalid label %s' % label_name)
            continue
        label = labels[0]
        
        features = session.query(sql.Feature).filter(sql.Feature.label_id==label.id) 
        count = atlas.commify( features.count() )
        atlas.info( "exporting label=%s, count=%s" % (label.name, count) )
        
        fname = atlas.join_paths( conf.EXPORT_DIR, '%s.%s.txt' % (conf.__name__, label_name) ) 
        atlas.info( 'exporting to %s' % fname)
        fp = file( fname, 'wt' )
        hdrs = formatter()
        if hdrs:
            fp.write( hdrs  )
        
        for data in sql.select_features(engine, label.id):
            strand = data['strand']
            if strand in strands:
                fp.write( formatter( data ) )

def tab_formatter( data=None ):
    "Allows the exporter to produce different types of outputs"
    if data is None:
        headers = 'name chrom strand start end value'.split()
        return atlas.join( headers, patt='%s\n')
    else:
        strand = data['strand']
        row = [ data['name'], data['chrom'], strand, data['start'], data['end'], data['value'] ]
        return atlas.join( row, patt='%s\n' )

def bed_formatter( data=None ):
    "Produces BED output"
    if data is None:
        return None
    else:
        strand = data['strand']
        start, end = int(data['start'])-1, int(data['end'])-1
        row = [  data['chrom'], start, end, data['name'], data['value'], strand  ]
        return atlas.join( row, patt='%s\n' )

def gff_formatter( data=None ):
    "Produces GFF output"
    if data is None:
        return None
    else:
        strand = data['strand']
        start, end = int(data['start']), int(data['end'])+1
        row = [  data['chrom'], 'GTRK', data['name'], start, end, data['value'], strand, '.', data['name']  ]
        return atlas.join( row, patt='%s\n' )

def wig_formatter( data=None ):
    "Produces wiggle output"
    if data is None:
        return 'track type=wiggle_0\n'
    else:
        strand = data['strand']
        row = [  data['chrom'], data['start'], data['end'], data['value'], strand  ]
        return atlas.join( row, patt='%s\n' )

@util.stop_on_error
def exporter( conf, formatter=tab_formatter, strands=None ):
    "Default exporter"
    strands = strands if strands else set('+-A')
    return producer( conf=conf, formatter=formatter, strands=strands )

gff_exporter = partial( exporter, formatter=gff_formatter)
bed_exporter = partial( exporter, formatter=gff_formatter)
tab_exporter = partial( exporter, formatter=tab_formatter)
wig_exporter = partial( exporter, formatter=wig_formatter)


def server( conf ):
    """
    Runs the webserver
    """
    
    # cannot run server withouth pychartdir
    try:
        import pychartdir
    except ImportError:
        atlas.fatal("pychartdir not found, get ChartDirector for python from:\nhttp://www.advsofteng.com/")
    
    import cherrypy
    from atlas.web import main

    global_conf = {
        'server.socket_host' : conf.SOCKET_HOST,
        'server.socket_port' : conf.SOCKET_PORT,
        'server.thread_pool' : conf.THREAD_POOL,
    }

    app_conf = { 

        conf.STATIC_URL :
            { 
                'tools.staticdir.on'  : True,
                'tools.staticdir.dir' : conf.STATIC_DIR,
            },

        '/'    :
            {
                'tools.sessions.on' : True,
                'tools.sessions.timeout' : 60,
            },
    }

    root = main.WebRoot( )
    root.set_conf( conf )

    cherrypy.config.update( global_conf )
    cherrypy.tree.mount( root, config=app_conf )
    cherrypy.server.quickstart()
    cherrypy.engine.start()

def test():
    """
    Main testrunnner
    """
    import doctest
    doctest.testmod( optionflags=doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE )

if __name__ == '__main__':
    test()
